/*
 * @Descripttion : 拖动排序
 * @Author       : QianFox Team
 * @Date         : 2022-03-08 15:14:19
 * @LastEditors  : QianFox Team
 * @LastEditTime : 2024-03-05 15:32:36
 */

function Dragsort() {
    this.CONTAINER = '.foxui-drag-container';
    this.HANDLE = '.foxui-drag .foxui-drag-handle';
    this.ITEM = '.foxui-drag-item';

    this.dragContainer = null; // 拖动元素父组容器节点 foxui-drag-container
    this.draging = null; // 正在拖动元素 foxui-drag-item
}

Dragsort.prototype = {
    _init() {
        this._drag();
    },

    _drag() {
        let that = this;

        // 鼠标按下时
        $(document).on('mousedown', this.HANDLE, function () {
            // 保存 拖动容器节点
            that.dragContainer = $(this).closest(that.CONTAINER)[0];

            // 添加 draggable 属性
            that._addDraggable(that.dragContainer);

            // 拖动开始
            that.dragContainer.ondragstart = function (event) {
                that._ondragstart(event);
            };
            // 拖动中
            that.dragContainer.ondragover = function (event) {
                that._ondragover(event);
            };
            // 拖动结束后
            that.dragContainer.ondragend = function (event) {
                that.dragContainer.ondragstart = null;
                that.dragContainer.ondragover = null;
                that._removeDraggable(that.dragContainer);
            };
        });

        // 鼠标松开时
        $(document).on('mouseup', this.HANDLE, function () {
            // 移除 draggable 属性
            that._removeDraggable(that.dragContainer);
        });
    },

    /**
     * @description: 拖动开始
     * @param {*} event
     * @return {*}
     * @Date: 2022-03-08 15:39:59
     */
    _ondragstart(event) {
        // dataTransfer.setData把拖动对象的数据存入其中，可以用dataTransfer.getData来获取数据
        // firefox设置了setData后元素才能拖动！！！！
        event.dataTransfer.setData('te', event.target.innerText); // 不能使用text，firefox会打开新tab
        // 保存正在拖动的节点
        this.draging = event.target;
    },

    _ondragover(event) {
        // 默认地，无法将数据/元素放置到其他元素中。如果需要设置允许放置，必须阻止对元素的默认处理方式
        event.preventDefault();
        let target = event.target;
        // 因为dragover会发生在ul上，所以要判断是不是 class 为 foxui-drag-item (是才发生)
        const hasDragClass = target.getAttribute('class') && target.getAttribute('class').indexOf('foxui-drag-item') > -1;
        // 因为嵌套，foxui-drag-item 的父级必须是 dragContainer
        if (hasDragClass && target.parentNode === this.dragContainer && target !== this.draging) {
            // 获取初始位置
            let targetRect = target.getBoundingClientRect();
            let dragingRect = this.draging.getBoundingClientRect();
            if (target) {
                // 判断是否动画元素
                if (target.animated) {
                    return;
                }
            }
            if (this._index(this.draging) < this._index(target)) {
                // 目标比元素大，插到其后面
                // extSibling下一个兄弟元素
                target.parentNode.insertBefore(this.draging, target.nextSibling);
            } else {
                // 目标比元素小，插到其前面
                target.parentNode.insertBefore(this.draging, target);
            }
            this._animate(dragingRect, this.draging);
            this._animate(targetRect, target);
        }
    },

    /**
     * @description: 移出添加元素的 draggable 属性
     * @param {*} dragContainer
     * @return {*}
     * @Date: 2022-03-08 15:47:22
     */
    _addDraggable(dragContainer) {
        let drag = $(dragContainer).children(this.ITEM);
        $(drag).each(function () {
            $(this).attr('draggable', true);
        });
    },

    /**
     * @description: 移出移动元素的 draggable 属性
     * @param {*} dragContainer
     * @return {*}
     * @Date: 2022-03-08 15:48:40
     */
    _removeDraggable(dragContainer) {
        let drag = $(dragContainer).children(this.ITEM);
        $(drag).each(function () {
            $(this).removeAttr('draggable');
        });
    },

    /**
     * @description: 获取元素在父元素中的index
     * @param {*} el
     * @return {*}
     * @Date: 2022-03-08 15:43:49
     */
    _index(el) {
        var index = 0;
        if (!el || !el.parentNode) {
            return -1;
        }
        // previousElementSibling：上一个兄弟元素
        while (el && (el = el.previousElementSibling)) {
            index++;
        }
        return index;
    },

    /**
     * @description: 触发动画
     * @param {*} prevRect
     * @param {*} target
     * @return {*}
     * @Date: 2022-03-08 15:46:32
     */
    _animate(prevRect, target) {
        var ms = 300;
        if (ms) {
            var currentRect = target.getBoundingClientRect();
            if (prevRect.nodeType === 1) {
                prevRect = prevRect.getBoundingClientRect();
            }
            this._css(target, 'transition', 'none');
            this._css(target, 'transform', 'translate3d(' + (prevRect.left - currentRect.left) + 'px,' + (prevRect.top - currentRect.top) + 'px,0)');
            target.offsetWidth; // 触发重绘
            this._css(target, 'transition', 'all ' + ms + 'ms');
            this._css(target, 'transform', 'translate3d(0,0,0)');
            // 事件到了之后把transition和transform清空
            clearTimeout(target.animated);
            target.animated = setTimeout(() => {
                this._css(target, 'transition', '');
                this._css(target, 'transform', '');
                target.animated = false;
            }, ms);
        }
    },

    /**
     * @description: 给元素添加style
     * @param {*} el
     * @param {*} prop
     * @param {*} val
     * @return {*}
     * @Date: 2022-03-08 15:46:08
     */
    _css(el, prop, val) {
        var style = el && el.style;
        if (style) {
            if (val === void 0) {
                if (document.defaultView && document.defaultView.getComputedStyle) {
                    val = document.defaultView.getComputedStyle(el, '');
                } else if (el.currentStyle) {
                    val = el.currentStyle;
                }
                return prop === void 0 ? val : val[prop];
            } else {
                if (!(prop in style)) {
                    prop = '-webkit-' + prop;
                }
                style[prop] = val + (typeof val === 'string' ? '' : 'px');
            }
        }
    },
};

let dragsort = new Dragsort();

export { dragsort };
